home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 11 / Mac Magazin and MacEasy Magazine CD - Issue 11.iso / Sharewarebibliothek / Entwickler / WASTE 1.1b1 Distribution / Demo Source / WEDemoWindows.p < prev    next >
Text File  |  1995-06-01  |  22KB  |  858 lines

  1. unit WEDemoWindows;
  2.  
  3. { WASTE DEMO PROJECT: }
  4. { Window Handling }
  5.  
  6. { Copyright © 1993-1995 Marco Piovanelli }
  7. { All Rights Reserved }
  8.  
  9. interface
  10.     uses
  11.         WEDemoIntf;
  12.  
  13. {$SETC WEDEMO_IC_SUPPORT = GENERATING68K}
  14.  
  15.     procedure DoDrag (hitPt: Point;
  16.                                     window: WindowPtr);
  17.     procedure DoGrow (hitPt: Point;
  18.                                     window: WindowPtr);
  19.     procedure DoZoom (partCode: Integer;
  20.                                     window: WindowPtr);
  21.     function DoContent (hitPt: Point;
  22.                                     var event: EventRecord;
  23.                                     window: WindowPtr): Boolean;
  24.     procedure DoKey (key: Char;
  25.                                     var event: EventRecord);
  26.     procedure DoUpdate (window: WindowPtr);
  27.     procedure DoActivate (activFlag: Boolean;
  28.                                     window: WindowPtr);
  29.     function CreateWindow (pFileSpec: FSSpecPtr): OSErr;
  30.     procedure DestroyWindow (window: WindowPtr);
  31.  
  32. implementation
  33.     uses
  34. {$IFC WEDEMO_IC_SUPPORT}
  35.         WEICSupport, 
  36. {$ENDC}
  37.         Aliases, ToolUtils, LongControls, WEDemoFiles;
  38.  
  39.     var
  40.  
  41. { static variables }
  42.  
  43.         sWEClickLoop: WEClickLoopUPP;
  44.         sWEScroller: WEScrollUPP;
  45.         sWEDragTranslator: WETranslateDragUPP;
  46.         sScrollProc: ControlActionUPP;
  47.         sScrollStep: Integer;                    { how many pixels to scroll (used by ScrollProc) }
  48.  
  49.     procedure MyDrawGrowIcon (wind: GrafPtr;
  50.                                     validate: Boolean);
  51. { the standard Toolbox trap _DrawGrowIcon draws two lines from the grow icon }
  52. { to the left and top margins of the window's content area }
  53. { these additional lines may create ugly dirt, so we use this routine to temporarily }
  54. { set the clip region to the grow icon rect }
  55. { in addition, if validate is TRUE, we call _ValidRect on the icon rect }
  56.         var
  57.             savePort: GrafPtr;
  58.             saveClip: RgnHandle;
  59.             r: Rect;
  60.     begin
  61.  
  62. { save port and set thePort to wind }
  63.         GetPort(savePort);
  64.         SetPort(wind);
  65.  
  66. { save the clip region }
  67.         saveClip := NewRgn;
  68.         GetClip(saveClip);
  69.  
  70. { calculate grow icon rect }
  71.         r.botRight := wind^.portRect.botRight;
  72.         r.top := r.bottom - (kBarWidth - 2);
  73.         r.left := r.right - (kBarWidth - 2);
  74.  
  75. { set clip region to grow icon rect }
  76.         ClipRect(r);
  77.  
  78. { call _DrawGrowIcon }
  79.         DrawGrowIcon(wind);
  80.  
  81. { if validate is TRUE, remove the grow icon rect from the update region }
  82.         if (validate) then
  83.             ValidRect(r);
  84.  
  85. { restore old clip region }
  86.         SetClip(saveClip);
  87.         DisposeRgn(saveClip);
  88.  
  89. { restore old port }
  90.         SetPort(savePort);
  91.  
  92.     end;  { MyDrawGrowIcon }
  93.  
  94.     procedure ScrollBarChanged (window: WindowPtr);
  95. { scroll text to reflect new scroll bar setting }
  96.         var
  97.             hWE: WEHandle;
  98.             viewRect, destRect: LongRect;
  99.     begin
  100.         hWE := DocumentPeek(window)^.hWE;
  101.         WEGetViewRect(viewRect, hWE);
  102.         WEGetDestRect(destRect, hWE);
  103.         WEScroll(viewRect.left - destRect.left - LCGetValue(DocumentPeek(window)^.scrollBars.h), viewRect.top - destRect.top - LCGetValue(DocumentPeek(window)^.scrollBars.v), hWE);
  104.     end;  { ScrollBarChanged }
  105.  
  106.     procedure AdjustBars (window: WindowPtr);
  107. { recalculate scroll bar settings based on the text total height and destination rectangle }
  108.         var
  109.             hWE: WEHandle;
  110.             savePort: GrafPtr;
  111.             viewRect, destRect: LongRect;
  112.             value: LongInt;
  113.             max: LongInt;
  114.             bar: ControlRef;
  115.             axis: VHSelect;
  116.     begin
  117.         GetPort(savePort);
  118.         SetPort(window);
  119.  
  120. { get view and destination rectangle }
  121.         hWE := DocumentPeek(window)^.hWE;
  122.         WEGetViewRect(viewRect, hWE);
  123.         WEGetDestRect(destRect, hWE);
  124.  
  125. { do for each axis }
  126.         for axis := v to h do
  127.             begin
  128.  
  129. { get scroll bar handle }
  130.                 bar := DocumentPeek(window)^.scrollBars.vh[axis];
  131.  
  132. { calculate new scroll bar settings }
  133.  
  134. { NOTE: (destRect.bottom - destRect.top) always equals the total text height because }
  135. { WASTE automatically updates destRect.bottom whenever line breaks are recalculated }
  136.  
  137.                 value := viewRect.topLeft.vh[axis] - destRect.topLeft.vh[axis];
  138.                 max := value + (destRect.botRight.vh[axis] - viewRect.botRight.vh[axis]);
  139.  
  140. { make sure max is always non-negative }
  141.                 if (max <= 0) then
  142.                     max := 0;
  143.  
  144. { reset the scroll bar }
  145.                 LCSetMax(bar, max);
  146.                 LCSetValue(bar, value);
  147.  
  148. { if value exceeds max then the bottom of the destination rectangle is above }
  149. { the bottom of the view rectangle: we need to scroll the text downward }
  150.                 if (value > max) then
  151.                     ScrollBarChanged(window);
  152.  
  153.             end;  { for axis }
  154.  
  155.         SetPort(savePort);
  156.  
  157.     end;  { AdjustBars }
  158.  
  159.     procedure ViewChanged (window: WindowPtr);
  160. { Fix its scroll bars and WE view rect when the window is created, }
  161. { or after it is resized or zoomed, or when the page is adjusted }
  162.         var
  163.             savePort: GrafPtr;
  164.             bar: ControlRef;
  165.             barRects: array[VHSelect] of Rect;
  166.             r: Rect;
  167.             viewRect: LongRect;
  168.             axis: VHSelect;
  169.     begin
  170.  
  171.         GetPort(savePort);
  172.         SetPort(window);
  173.  
  174. { recalculate the correct rectangles for the text area and the scroll bars, }
  175. { based on the window's port rect }
  176.         with window^.portRect do
  177.             begin
  178.                 SetRect(barRects[v], right - (kBarWidth - 1), -1, right + 1, bottom - (kBarWidth - 2));
  179.                 SetRect(barRects[h], -1, bottom - (kBarWidth - 1), right - (kBarWidth - 2), bottom + 1);
  180.                 SetRect(r, 0, 0, right - (kBarWidth - 1), bottom - (kBarWidth - 1));
  181.                 InsetRect(r, kTextMargin, kTextMargin);
  182.                 WERectToLongRect(r, viewRect);
  183.             end;
  184.  
  185. { resize the text area }
  186.         WESetViewRect(viewRect, DocumentPeek(window)^.hWE);
  187.  
  188. { move and resize the control bars }
  189.         for axis := v to h do
  190.             begin
  191.                 bar := DocumentPeek(window)^.scrollBars.vh[axis];
  192.                 r := barRects[axis];
  193.                 MoveControl(bar, r.left, r.top);
  194.                 SizeControl(bar, r.right - r.left, r.bottom - r.top);
  195.                 ValidRect(r);
  196.             end;  { for axis }
  197.  
  198. { reset thumb positions and the max values of the control bars }
  199.         AdjustBars(window);
  200.  
  201. { redraw the control bars }
  202.         ShowControl(DocumentPeek(window)^.scrollBars.v);
  203.         ShowControl(DocumentPeek(window)^.scrollBars.h);
  204.  
  205.         SetPort(savePort);
  206.  
  207.     end;  { ViewChanged }
  208.  
  209.     procedure DoDrag (hitPt: Point;
  210.                                     window: WindowPtr);
  211.         var
  212.             dragRect: Rect;
  213.     begin
  214.         dragRect := GetGrayRgn^^.rgnBBox;
  215.         DragWindow(window, hitPt, dragRect);
  216.     end;  { DoDrag }
  217.  
  218.     procedure Resize (newSize: Point;
  219.                                     window: WindowPtr);
  220.         var
  221.             savePort: GrafPtr;
  222.             viewRect: LongRect;
  223.             r: Rect;
  224.             tempRgn, dirtyRgn: RgnHandle;
  225.     begin
  226.  
  227.         GetPort(savePort);
  228.         SetPort(window);
  229.  
  230. { create temporary regions for calculations }
  231.         tempRgn := NewRgn;
  232.         dirtyRgn := NewRgn;
  233.  
  234. { save old text region }
  235.         WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  236.         WELongRectToRect(viewRect, r);
  237.         RectRgn(tempRgn, r);
  238.  
  239. { erase the old grow icon rect }
  240.         r.botRight := window^.portRect.botRight;
  241.         r.top := r.bottom - (kBarWidth - 2);
  242.         r.left := r.right - (kBarWidth - 2);
  243.         EraseRect(r);
  244.  
  245. { hide the scroll bars }
  246.         HideControl(DocumentPeek(window)^.scrollBars.v);
  247.         HideControl(DocumentPeek(window)^.scrollBars.h);
  248.  
  249. { perform the actual resizing of window, redraw scroll bars and grow icon}
  250.         SizeWindow(window, newSize.h, newSize.v, false);
  251.         ViewChanged(window);
  252.         MyDrawGrowIcon(window, true);
  253.  
  254. { calculate the dirty region (to be updated) }
  255.         WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  256.         WELongRectToRect(viewRect, r);
  257.         RectRgn(dirtyRgn, r);
  258.         XOrRgn(dirtyRgn, tempRgn, dirtyRgn);
  259.         with window^.portRect do
  260.             SetRectRgn(tempRgn, left, top, right - (kBarWidth - 1), bottom - (kBarWidth - 1));
  261.         SectRgn(dirtyRgn, tempRgn, dirtyRgn);
  262.  
  263. { mark the dirty region as invalid }
  264.         InvalRgn(dirtyRgn);
  265.  
  266. { throw away temporary regions }
  267.         DisposeRgn(tempRgn);
  268.         DisposeRgn(dirtyRgn);
  269.  
  270.         SetPort(savePort);
  271.  
  272.     end;  { Resize }
  273.  
  274.     procedure DoGrow (hitPt: Point;
  275.                                     window: WindowPtr);
  276.         const
  277.             kMinWindowWidth = 200;
  278.             kMinWindowHeight = 80;
  279.         var
  280.             sizeRect: Rect;
  281.             newSize: LongInt;
  282.     begin
  283.         SetRect(sizeRect, kMinWindowWidth, kMinWindowHeight, maxint, maxint);
  284.         newSize := GrowWindow(window, hitPt, sizeRect);
  285.         if (newSize <> 0) then
  286.             Resize(Point(newSize), window);
  287.     end;  { DoGrow }
  288.  
  289.     procedure DoZoom (partCode: Integer;
  290.                                     window: WindowPtr);
  291.         var
  292.             savePort: GrafPtr;
  293.             viewRect: LongRect;
  294.             textRect: Rect;
  295.     begin
  296.  
  297.         GetPort(savePort);
  298.         SetPort(window);
  299.  
  300.         EraseRect(window^.portRect);
  301.         HideControl(DocumentPeek(window)^.scrollBars.v);
  302.         HideControl(DocumentPeek(window)^.scrollBars.h);
  303.         ZoomWindow(window, partCode, false);
  304.         ViewChanged(window);
  305.         WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  306.         WELongRectToRect(viewRect, textRect);
  307.         InvalRect(textRect);
  308.  
  309.         SetPort(savePort);
  310.  
  311.     end;  { DoZoom }
  312.  
  313.     procedure ScrollProc (bar: ControlRef;
  314.                                     partCode: Integer);
  315.  
  316. { this is a callback routine called by the Toolbox Control Manager }
  317. { move the scroll bar thumb and scroll the text accordingly }
  318.  
  319.         var
  320.             value, step: LongInt;
  321.     begin
  322.  
  323.         if (partCode = 0) then
  324.             Exit(ScrollProc);
  325.  
  326.         value := LCGetValue(bar);
  327.         step := sScrollStep;
  328.  
  329.         if ((value < LCGetMax(bar)) and (step > 0)) or ((value > 0) and (step < 0)) then
  330.             begin
  331.                 LCSetValue(bar, value + step);
  332.                 ScrollBarChanged(FrontWindow);
  333.             end;
  334.     end;  { ScrollProc }
  335.  
  336.     procedure DoScrollBar (hitPt: Point;
  337.                                     modifiers: Integer;
  338.                                     window: WindowPtr);
  339.         var
  340.             bar: ControlRef;
  341.             viewRect: LongRect;
  342.             axis: VHSelect;
  343.             partCode, step: Integer;
  344.     begin
  345.  
  346. { find out which scroll bar was hit (if any) and in which part }
  347.         partCode := FindControl(hitPt, window, bar);
  348.  
  349.         if (bar <> nil) then
  350.  
  351. { dispatch on partCode }
  352.             if (partCode = kInIndicatorControlPart) then
  353.                 begin
  354.  
  355. { click in thumb: call TrackControl with no actionProc and adjust text }
  356.                     partCode := TrackControl(bar, hitPt, nil);
  357.                     LCSynch(bar);
  358.                     ScrollBarChanged(window);
  359.  
  360.                 end
  361.             else
  362.                 begin
  363.  
  364. { click in a bar, but not in thumb }
  365. { which scroll bar was hit? }
  366.                     if (bar = DocumentPeek(window)^.scrollBars.v) then
  367.                         axis := v
  368.                     else
  369.                         axis := h;
  370.  
  371. { get text view rectangle }
  372.                     WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  373.  
  374. { dispatch on partCode }
  375.                     case partCode of
  376.  
  377.                         kInUpButtonControlPart: 
  378.                             if (BAND(modifiers, optionKey) = 0) then
  379.                                 step := -kScrollDelta
  380.                             else
  381.                                 step := -1;
  382.  
  383.                         kInDownButtonControlPart: 
  384.                             if (BAND(modifiers, optionKey) = 0) then
  385.                                 step := +kScrollDelta
  386.                             else
  387.                                 step := +1;
  388.  
  389.                         kInPageUpControlPart: 
  390.                             step := -(viewRect.botRight.vh[axis] - viewRect.topLeft.vh[axis]) + kScrollDelta;
  391.  
  392.                         kInPageDownControlPart: 
  393.                             step := (viewRect.botRight.vh[axis] - viewRect.topLeft.vh[axis]) - kScrollDelta;
  394.  
  395.                         otherwise
  396.                             step := 0;
  397.                     end;  { case }
  398.  
  399. { save step in a static variable for our ScrollProc callback }
  400.                     sScrollStep := step;
  401.  
  402. { create the routine descriptor for the control action procedure, if we haven't already }
  403.                     if (sScrollProc = nil) then
  404.                         sScrollProc := NewControlActionProc(@ScrollProc);
  405.  
  406. { track the mouse }
  407.                     partCode := TrackControl(bar, hitPt, sScrollProc);
  408.  
  409.                 end;
  410.     end;  { DoScrollBar }
  411.  
  412.     function ClickLoop (hWE: WEHandle): Boolean;
  413.  
  414. { this is a callback routine repeatedly called by WEClick while tracking the mouse }
  415. { if the mouse goes out of the text rect, scroll the text and adjust the scroll bars }
  416.  
  417.         var
  418.             window: WindowPtr;
  419.             textRect: LongRect;
  420.             mouseLoc: Point;
  421.             bar: ControlRef;
  422.             oldValue: LongInt;
  423.             delta: Integer;
  424.             axis: VHSelect;
  425.     begin
  426.  
  427. { return TRUE so WEClick keeps tracking the mouse }
  428.         ClickLoop := true;
  429.  
  430. { retrieve the window pointer stored in the WE instance as a "reference constant" }
  431.         if (WEGetInfo(weRefCon, @window, hWE) <> noErr) then
  432.             Exit(ClickLoop);
  433.  
  434. { get text rect and mouse location (in local coords) }
  435.         WEGetViewRect(textRect, hWE);
  436.         GetMouse(mouseLoc);
  437.  
  438.         for axis := v to h do
  439.             begin
  440.                 bar := DocumentPeek(window)^.scrollBars.vh[axis];
  441.                 oldValue := LCGetValue(bar);
  442.                 delta := mouseLoc.vh[axis] - textRect.botRight.vh[axis];
  443.                 if (delta > 0) then
  444.                     begin
  445.                         if (oldValue < LCGetMax(bar)) then
  446.                             LCSetValue(bar, oldValue + kScrollDelta);
  447.                     end
  448.                 else
  449.                     begin
  450.                         delta := textRect.topLeft.vh[axis] - mouseLoc.vh[axis];
  451.                         if (delta > 0) then
  452.                             begin
  453.                                 if (oldValue > 0) then
  454.                                     LCSetValue(bar, oldValue - kScrollDelta);
  455.                             end;
  456.                     end;
  457.             end;  { for axis }
  458.  
  459. { scroll the text to match current scroll bar settings }
  460.         ScrollBarChanged(window);
  461.  
  462.     end;  { ClickLoop }
  463.  
  464.     procedure TextScrolled (hWE: WEHandle);
  465.  
  466. { This is a callback routine called whenever the text is scrolled automatically. }
  467. { Since auto-scrolling is enabled, WEScroll may be invoked internally by WASTE }
  468. { in many different circumstances, and we want to be notified when this happens }
  469. { so we can adjust the scroll bars }
  470.  
  471.         var
  472.             window: WindowPtr;
  473.     begin
  474.  
  475. { retrieve the window pointer stored in the WE instance as a "reference constant" }
  476.         if (WEGetInfo(weRefCon, @window, hWE) <> noErr) then
  477.             Exit(TextScrolled);
  478.  
  479. { make sure scroll bars are in synch with the destination rectangle }
  480.         AdjustBars(window);
  481.  
  482.     end;  { TextScrolled }
  483.  
  484.     function DoContent (hitPt: Point;
  485.                                     var event: EventRecord;
  486.                                     window: WindowPtr): Boolean;
  487.         var
  488.             selStart, selEnd: LongInt;
  489.             selRgn: RgnHandle;
  490.             inBackground, handleClick: Boolean;
  491.             viewRect: LongRect;
  492.             textRect: Rect;
  493.             savePort: GrafPtr;
  494.     begin
  495.         DoContent := false;        { false means click should not activate this window }
  496.  
  497. { is this window in the background? }
  498.         inBackground := (WindowPeek(window)^.hilited = false);
  499.  
  500. { set the port to our window's port }
  501.         GetPort(savePort);
  502.         SetPort(window);
  503.  
  504. { convert the point to local coordinates }
  505.         GlobalToLocal(hitPt);
  506.  
  507. { a click in an inactive window should normally activate it, }
  508. { but the availability of the Drag Manager introduces an exception to this rule: }
  509. { a click in the background selection may start a drag gesture, }
  510. { without activating the window }
  511.  
  512.         if (inBackground) then
  513.             if (gHasDragAndDrop) then
  514.                 begin
  515.                     WEGetSelection(selStart, selEnd, DocumentPeek(window)^.hWE);
  516.                     selRgn := WEGetHiliteRgn(selStart, selEnd, DocumentPeek(window)^.hWE);
  517.                     handleClick := PtInRgn(hitPt, selRgn) & WaitMouseMoved(event.where);
  518.                     DisposeRgn(selRgn);
  519.                 end
  520.             else
  521.                 handleClick := false            { no Drag Manager: never click-through }
  522.         else
  523.             handleClick := true;                { window is frontmost; always handle click }
  524.  
  525.         if (handleClick) then
  526.             begin
  527.  
  528. { get view rectangle in short coordinates }
  529.                 WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  530.                 WELongRectToRect(viewRect, textRect);
  531.  
  532.                 if PtInRect(hitPt, textRect) then
  533. {$IFC WEDEMO_IC_SUPPORT}
  534.                     ICAwareWEClick(hitPt, event.modifiers, event.when, DocumentPeek(window)^.hWE)
  535. {$ELSEC}
  536.                     WEClick(hitPt, event.modifiers, event.when, DocumentPeek(window)^.hWE)
  537. {$ENDC}
  538.                 else
  539.                     DoScrollBar(hitPt, event.modifiers, window);
  540.  
  541.             end
  542.         else
  543.             DoContent := inBackground;
  544.  
  545. { restore the port }
  546.         SetPort(savePort);
  547.  
  548.     end;  { DoContent }
  549.  
  550.     procedure DoScrollKey (keyCode: SignedByte;
  551.                                     window: WindowPtr);
  552.         var
  553.             bar: ControlRef;
  554.             v: LongInt;
  555.             viewRect: LongRect;
  556.     begin
  557.         bar := DocumentPeek(window)^.scrollBars.v;
  558.  
  559. { do nothing if the scroll bar isn't active }
  560.         if (bar^^.contrlHilite <> kCtlActive) then
  561.             Exit(DoScrollKey);
  562.  
  563. { get current scroll bar value }
  564.         v := LCGetValue(bar);
  565.  
  566. { get text view rect }
  567.         WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  568.  
  569.         case keyCode of
  570.  
  571.             keyPgUp: 
  572.                 v := v - (viewRect.bottom - viewRect.top) + kScrollDelta;
  573.  
  574.             keyPgDn: 
  575.                 v := v + (viewRect.bottom - viewRect.top) - kScrollDelta;
  576.  
  577.             keyHome: 
  578.                 v := 0;
  579.  
  580.             keyEnd: 
  581.                 v := maxLongInt;
  582.  
  583.             otherwise
  584.                 ;
  585.         end;  { case }
  586.  
  587. { set the new scroll bar value and scroll the text pane accordingly }
  588.         LCSetValue(bar, v);
  589.         ScrollBarChanged(window);
  590.  
  591.     end;  { DoScrollKey }
  592.  
  593.     procedure DoKey (key: Char;
  594.                                     var event: EventRecord);
  595.         var
  596.             window: WindowPtr;
  597.             keyCode: SignedByte;
  598.     begin
  599.         window := FrontWindow;
  600.  
  601. { do nothing if no window is active }
  602.         if (window = nil) then
  603.             Exit(DoKey);
  604.  
  605. { extract virtual key code from event record }
  606.         keyCode := BSR(BAND(event.message, keyCodeMask), 8);
  607.  
  608. { page movement keys are handled by DoScrollKey }
  609.         if (keyCode in [keyPgUp, keyPgDn, keyHome, keyEnd]) then
  610.             DoScrollKey(keyCode, window)
  611.         else
  612.             WEKey(key, event.modifiers, DocumentPeek(window)^.hWE);
  613.  
  614.     end;  { DoKey }
  615.  
  616.     procedure DoUpdate (window: WindowPtr);
  617.         var
  618.             savePort: GrafPtr;
  619.             updateRgn: RgnHandle;
  620.     begin
  621.         GetPort(savePort);
  622.         SetPort(window);
  623.         BeginUpdate(window);
  624.  
  625. { BeginUpdate sets the window visRgn to the region to update }
  626.         updateRgn := window^.visRgn;
  627.  
  628. { erase update region }
  629.         EraseRgn(updateRgn);
  630.  
  631. { draw scroll bars }
  632.         UpdateControls(window, updateRgn);
  633.  
  634. { draw grow icon }
  635.         MyDrawGrowIcon(window, false);
  636.  
  637. { draw text }
  638.         WEUpdate(updateRgn, DocumentPeek(window)^.hWE);
  639.  
  640.         EndUpdate(window);
  641.         SetPort(savePort);
  642.  
  643.     end;  { DoUpdate }
  644.  
  645.     procedure DoActivate (activFlag: Boolean;
  646.                                     window: WindowPtr);
  647.         var
  648.             savePort: GrafPtr;
  649.             bar: ControlRef;
  650.             barHilite: Integer;
  651.             barRect: Rect;
  652.             axis: VHSelect;
  653.             menuID: Integer;
  654.     begin
  655.  
  656. { set up the port }
  657.         GetPort(savePort);
  658.         SetPort(window);
  659.  
  660.         if (activFlag) then
  661.             begin
  662.                 WEActivate(DocumentPeek(window)^.hWE);
  663.                 barHilite := kCtlActive;
  664.             end
  665.         else
  666.             begin
  667.                 WEDeactivate(DocumentPeek(window)^.hWE);
  668.                 barHilite := kCtlBackground;
  669.             end;
  670.  
  671. { redraw the grow icon (and validate its rect) }
  672.         MyDrawGrowIcon(window, true);
  673.  
  674. { redraw the scroll bars with the new highlighting (and validate their rects) }
  675.         for axis := v to h do
  676.             begin
  677.                 bar := DocumentPeek(window)^.scrollBars.vh[axis];
  678.                 HiliteControl(bar, barHilite);
  679.                 barRect := bar^^.contrlRect;
  680.                 ValidRect(barRect);
  681.             end;
  682.  
  683. { dim or undim text-related menus }
  684.         for menuID := kMenuEdit to kMenuFeatures do
  685.             if (activFlag) then
  686.                 EnableItem(GetMenuHandle(menuID), 0)
  687.             else
  688.                 DisableItem(GetMenuHandle(menuID), 0);
  689.  
  690. { invalidate the menu bar }
  691.         InvalMenuBar;
  692.  
  693. { restore the port }
  694.         SetPort(savePort);
  695.  
  696.     end;  { DoActivate }
  697.  
  698.     function CreateWindow (pFileSpec: FSSpecPtr): OSErr;
  699.         var
  700.             pWRecord: Ptr;
  701.             window: WindowPtr;
  702.             hWE: WEHandle;
  703.             bar: ControlRef;
  704.             axis: VHSelect;
  705.             fileInfo: FInfo;
  706.             textRect: Rect;
  707.             longTextRect: LongRect;
  708.  
  709.         procedure CheckErr (err: OSErr);
  710.         begin
  711.             if (err <> noErr) then
  712.                 begin
  713.                     CreateWindow := err;
  714.                     ErrorAlert(err);
  715.  
  716. { here we should destroy partially allocated data structures to avoid memory leaks }
  717. { but, hey, this is just a demo, not a real-world application }
  718.                     Exit(CreateWindow);
  719.                 end;
  720.         end;  { CheckErr }
  721.  
  722.     begin
  723.         CreateWindow := noErr;
  724.  
  725. { allocate a non-relocatable block to hold a document record }
  726.         pWRecord := NewPtrClear(SizeOf(DocumentRecord));
  727.         CheckErr(MemError);
  728.  
  729. { create the window from a 'WIND' template; the window is initially invisible }
  730. { if Color QuickDraw is available, create a color window }
  731.         if (gHasColorQD) then
  732.             window := GetNewCWindow(kWindowTemplateID, pWRecord, WindowPtr(-1))
  733.         else
  734.             window := GetNewWindow(kWindowTemplateID, pWRecord, WindowPtr(-1));
  735.  
  736. { make sure we got a window }
  737.         if (window = nil) then
  738.             begin
  739.                 DisposePtr(pWRecord);
  740.                 CheckErr(memFullErr);
  741.             end;
  742.  
  743. { calculate the text rectangle }
  744.         textRect := window^.portRect;
  745.         textRect.right := textRect.right - (kBarWidth - 1);
  746.         textRect.bottom := textRect.bottom - (kBarWidth - 1);
  747.         InsetRect(textRect, kTextMargin, kTextMargin);
  748.         WERectToLongRect(textRect, longTextRect);
  749.  
  750. { before calling WENew, set the port to gWindow, }
  751. { so the WE instance knows where to draw }
  752.         SetPort(window);
  753.  
  754. { create the WE instance, enabling certain features }
  755.         CheckErr(WENew(longTextRect, longTextRect, weDoAutoScroll + weDoOutlineHilite + weDoUndo + weDoIntCutAndPaste + weDoDragAndDrop + weDoUseTempMem + weDoDrawOffscreen, hWE));
  756.  
  757. { set the alignment to weFlushLeft so "slop recalc" is disabled }
  758.         WESetAlignment(weFlushLeft, hWE);
  759.  
  760. { save a reference to the window in the WE instance }
  761.         CheckErr(WESetInfo(weRefCon, @window, hWE));
  762.  
  763. { now the other way around: save the WE handle in the document record }
  764.         DocumentPeek(window)^.hWE := hWE;
  765.  
  766. { create routine descriptors for the WASTE callbacks }
  767.         if (sWEClickLoop = nil) then
  768.             begin
  769.                 sWEClickLoop := NewWEClickLoopProc(@ClickLoop);
  770.                 sWEScroller := NewWEScrollProc(@TextScrolled);
  771.                 sWEDragTranslator := NewWETranslateDragProc(@TranslateDrag);
  772.             end;  { if first time }
  773.  
  774. { set up our callbacks }
  775.         CheckErr(WESetInfo(weClickLoop, @sWEClickLoop, hWE));
  776.         CheckErr(WESetInfo(weScrollProc, @sWEScroller, hWE));
  777.         CheckErr(WESetInfo(weTranslateDragHook, @sWEDragTranslator, hWE));
  778.  
  779.         for axis := v to h do
  780.             begin
  781.  
  782. { create a scroll bar from a 'CNTL' template }
  783.                 bar := GetNewControl(kScrollBarTemplateID, window);
  784.                 if (bar = nil) then
  785.                     CheckErr(-1);
  786.                 HiliteControl(bar, kCtlBackground);
  787.  
  788. { attach a LongControl record to the scroll bar; this allows us to use long }
  789. { settings and thus to scroll text taller than 32,767 pixels }
  790.                 CheckErr(LCAttach(bar));
  791.  
  792. { save control handle in the document record }
  793.                 DocumentPeek(window)^.scrollBars.vh[axis] := bar;
  794.  
  795.             end;  { for axis }
  796.  
  797. { ViewChanged adjusts the scroll bars rectangles to the window frame }
  798.         ViewChanged(window);
  799.  
  800. { if pFileSpec is not NIL, it points to a file to read }
  801.         if (pFileSpec <> nil) then
  802.             begin
  803.  
  804. { turn the cursor into a wristwatch because this can be a lengthy operation }
  805.                 SetCursor(GetCursor(watchCursor)^^);
  806.  
  807. { retrieve file information }
  808.                 CheckErr(FSpGetFInfo(pFileSpec^, fileInfo));
  809.  
  810. { make sure we recognize the file type }
  811.                 if (fileInfo.fdType <> kTypeText) then
  812.                     CheckErr(-1);
  813.  
  814. { read in the file }
  815.                 CheckErr(ReadTextFile(pFileSpec, hWE));
  816.  
  817. { set the window title to the file name }
  818.                 SetWTitle(window, pFileSpec^.name);
  819.  
  820. { create an alias to keep track of the file }
  821.                 CheckErr(NewAlias(nil, pFileSpec^, AliasHandle(DocumentPeek(window)^.fileAlias)));
  822.  
  823.             end;  { if pFileSpec <> NIL }
  824.  
  825. { adjust scroll bar settings based on the total text height }
  826.         AdjustBars(window);
  827.  
  828. { show the document window }
  829.         ShowWindow(window);
  830.  
  831.     end;  { CreateWindow }
  832.  
  833.     procedure DestroyWindow (window: WindowPtr);
  834.         var
  835.             menuID: Integer;
  836.     begin
  837.  
  838. { destroy the WE record }
  839.         WEDispose(DocumentPeek(window)^.hWE);
  840.  
  841. { destroy the LongControl records attached to the scroll bars }
  842.         LCDetach(DocumentPeek(window)^.scrollBars.v);
  843.         LCDetach(DocumentPeek(window)^.scrollBars.h);
  844.  
  845. { dispose of the file alias, if any }
  846.         ForgetHandle(DocumentPeek(window)^.fileAlias);
  847.  
  848. { destroy the window record and all associated data structures }
  849.         DisposeWindow(window);
  850.  
  851. { disable the text-editing menus }
  852.         for menuID := kMenuFont to kMenuFeatures do
  853.             DisableItem(GetMenuHandle(menuID), 0);
  854.         InvalMenuBar;
  855.  
  856.     end;  { DestroyWindow }
  857.  
  858. end.